package net.youdi.gateway.filter;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import net.youdi.gateway.exception.GateWayException;
import net.youdi.gateway.options.FilterOrderEnum;
import net.youdi.gateway.properties.AuthenticationProperties;
import net.youdi.gateway.properties.GatewayProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Map;

/**
 * Gateway Context Filter
 * @description 接口鉴权Filter
 */
@Slf4j
@AllArgsConstructor
public class AuthenticationFilter implements GlobalFilter, Ordered {

    private final WebClient.Builder webClient;
    private final AuthenticationProperties authenticationProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String uri = request.getURI().getRawPath();
        log.info("check token and user permission....{}",uri);
        //是否允许匿名登录
        if (authenticationProperties.isPermissionForAnonymous(uri)){
            return chain.filter(exchange);
        }
        final Token token = getToken(request);
        if (token==null){
            throw new GateWayException("请先登录", HttpStatus.FORBIDDEN.value());
        }
        /*if (authenticationProperties.isPermissionForLogin(uri)){
            return chain.filter(exchange);
        }*/
        String method = request.getMethod().name();
        Mono<Object> bodySpec = this.webClient
                .baseUrl("http://authority/authentication/check?url="+uri+"&method="+method)
                .build()
                .method(HttpMethod.GET)
                .headers(httpHeaders -> {
                    httpHeaders.add(authenticationProperties.getTokenName(),token.getToken());
                }).retrieve().bodyToMono(Object.class);
        return bodySpec.retry(3)
               .doOnNext(b->{
                    if (b instanceof Map){
                        Map r = (Map)b;
                        Integer code = (Integer) r.get("code");
                        if (code != 0){
                            log.error("权限认证失败--->"+r);
                            throw new GateWayException(String.valueOf(r.get("message")),code);
                        }
                        Map data = (Map) r.get("data");
                        //替换token请求头
                        exchange.mutate().request(
                                request.mutate()
                                .header(authenticationProperties.getTokenName(), String.valueOf(data.get(authenticationProperties.getTokenName()))).build());
                        exchange.getAttributes().put(GatewayProperties.USER_KEY,data.get("userId"));
                    }
                }).then(chain.filter(exchange));
    }

    public Token getToken(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String token = headers.getFirst(authenticationProperties.getTokenName());
        if (token==null || token.equals("")){
            token = request.getQueryParams().getFirst(authenticationProperties.getTokenName());
        }
        if (token != null && !"".equals(token)){
            return new Token().setToken(token);
        }
        return null;
    }

    @Accessors(chain = true)
    class Token{
        @Setter
        @Getter
        private String token;

    }

    @Override
    public int getOrder() {
        return FilterOrderEnum.GATEWAY_CONTEXT_FILTER.getOrder();
    }
}